﻿using System;
using System.IO;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;


namespace com.hebg3.app.zip {
  /**压缩类
   */
  public class Ziper {
    /// <summary>压缩文件 和 文件夹
    /// </summary>
    /// <param name="FileToZip">待压缩的文件或文件夹，全路径格式</param>
    /// <param name="ZipedFile">压缩后生成的压缩文件名，全路径格式</param>
    /// <returns></returns>
    public static bool zip(String fileToZip, String zipedFile, String password) {
      //如果是文件夹,则压缩文件夹
      if( Directory.Exists(fileToZip) ) {
        return zipFileDictory(fileToZip, zipedFile, password);
        //如果是文件则压缩单个文件
      } else if( File.Exists(fileToZip) ) {
        return zipFile(fileToZip, zipedFile, password);
      } else {
        return false;
      }
    }
    /// <summary>
    /// 压缩目录
    /// </summary>
    /// <param name="FolderToZip">待压缩的文件夹，全路径格式</param>
    /// <param name="ZipedFile">压缩后的文件名，全路径格式</param>
    /// <returns></returns>
    private static bool zipFileDictory(string folderToZip, string zipedFile, String password) {
      bool result;//压缩是否成功的标识
      //如果文件夹不存在,返回false
      if( !Directory.Exists(folderToZip) ) {
        return false;
      }
      //创建zip输出流
      ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(zipedFile));
      zipOutputStream.SetLevel(6);//压缩级别
      //如果密码不为空,则设置密码
      if( password != null ) {
        zipOutputStream.Password = password;
      }

      //压缩文件夹
      result = zipFileDictory(folderToZip, zipOutputStream, "");

      zipOutputStream.Finish();
      zipOutputStream.Close();

      return result;
    }

    /// <summary>
    /// 压缩文件
    /// </summary>
    /// <param name="FileToZip">要进行压缩的文件名</param>
    /// <param name="ZipedFile">压缩后生成的压缩文件名</param>
    /// <returns></returns>
    private static bool zipFile(string fileToZip, string zipedFile, String password) {
      //如果文件没有找到，则报错
      if( !File.Exists(fileToZip) ) {
        throw new System.IO.FileNotFoundException("指定要压缩的文件: " + fileToZip + " 不存在!");
      }
      //FileStream fs = null;
      FileStream zipFile = null;
      ZipOutputStream zipStream = null;
      ZipEntry zipEntry = null;

      bool result = true;
      try {
        zipFile = File.OpenRead(fileToZip);
        byte[] buffer = new byte[zipFile.Length];
        zipFile.Read(buffer, 0, buffer.Length);
        zipFile.Close();


        zipFile = File.Create(zipedFile);
        zipStream = new ZipOutputStream(zipFile);
        if( password != null ) {
          zipStream.Password = password;
        }
        //
        zipEntry = new ZipEntry(Path.GetFileName(fileToZip));
        zipStream.PutNextEntry(zipEntry);
        zipStream.SetLevel(6);


        zipStream.Write(buffer, 0, buffer.Length);
      } catch {
        result = false;
      } finally {
        if( zipEntry != null ) {
          zipEntry = null;
        }
        if( zipStream != null ) {
          zipStream.Finish();
          zipStream.Close();
        }
        if( zipFile != null ) {
          zipFile.Close();
          zipFile = null;
        }
        GC.Collect();
        GC.Collect(1);
      }


      return result;
    }

    /// <summary>
    /// 递归压缩文件夹方法
    /// </summary>
    /// <param name="FolderToZip"></param>
    /// <param name="s"></param>
    /// <param name="ParentFolderName"></param>
    private static bool zipFileDictory(string folderToZip, ZipOutputStream zipOutputStream, string parentFolderName) {
      bool result = true;//标识成功与否的布尔型值
      string[] folders, fileNames;//文件名数组
      ZipEntry entry = null;//Entry
      FileStream fs = null;//文件流
      Crc32 crc = new Crc32();
      try {
        //创建当前文件夹的entry
        entry = new ZipEntry(Path.Combine(parentFolderName, Path.GetFileName(folderToZip) + "/"));  //加上 “/” 才会当成是文件夹创建
        //将entry放入zip输出流
        zipOutputStream.PutNextEntry(entry);
        zipOutputStream.Flush();
        //先压缩文件，再递归压缩文件夹 Directory.GetFiles方法得到当前文件夹下所有文件
        fileNames = Directory.GetFiles(folderToZip);
        //迭代每个文件
        foreach( string file in fileNames ) {
          //文件流读入文件
          fs = File.OpenRead(file);
          //构建byte数组
          byte[] buffer = new byte[fs.Length];
          //将文件流的内容放入byte数组
          fs.Read(buffer, 0, buffer.Length);
          //构建ZipEntry,参数为指定放压缩文件的目录/的要压缩的文件夹名/文件名
          entry = new ZipEntry(Path.Combine(parentFolderName, Path.GetFileName(folderToZip) + "/" + Path.GetFileName(file)));
          //时间
          entry.DateTime = DateTime.Now;
          //大小
          entry.Size = fs.Length;
          fs.Close();

          crc.Reset();
          crc.Update(buffer);

          entry.Crc = crc.Value;

          zipOutputStream.PutNextEntry(entry);
          //将byte数组中的内容写入zip输出流
          zipOutputStream.Write(buffer, 0, buffer.Length);
        }
      } catch {
        result = false;
      } finally {
        if( fs != null ) {
          fs.Close();
          fs = null;
        }
        if( entry != null ) {
          entry = null;
        }
        GC.Collect();
        GC.Collect(1);
      }
      //遍历所有子文件夹Directory.GetDirectories方法得到当前文件夹下所有子文件夹
      folders = Directory.GetDirectories(folderToZip);
      //迭代压缩每个子文件夹
      foreach( string folder in folders ) {
        if( !zipFileDictory(folder, zipOutputStream, Path.Combine(parentFolderName, Path.GetFileName(folderToZip))) ) {
          return false;
        }
      }

      return result;
    }


   



  }

}
